Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved expression-validation and SQL-dialect selection issues could produce incorrect metric conversions.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
What changed in this PR
Fixes dbt metric conversion to preserve aggregate semantics and report unsupported expressions.
Changes:
- Decomposes supported aggregates into scalar expressions plus aggregation operators.
- Reports and omits unsupported or non-SQL expressions.
- Adds CLI warnings, tests, fixtures, and documentation.
| File | Description |
|---|---|
converters/dbt/tests/test_ossie_to_msi.py |
Adds conversion, unsupported-case, and round-trip tests. |
converters/dbt/tests/test_cli.py |
Tests CLI warning output. |
converters/dbt/tests/helpers.py |
Supports dialect-specific test metrics. |
converters/dbt/src/ossie_dbt/ossie_to_msi.py |
Converts metrics and reports unsupported expressions. |
converters/dbt/src/ossie_dbt/expression_utils.py |
Parses aggregate expressions. |
converters/dbt/src/ossie_dbt/converter_issues.py |
Adds the unsupported-expression issue type. |
converters/dbt/src/ossie_dbt/cli.py |
Surfaces conversion warnings. |
converters/dbt/README.md |
Documents supported conversion behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if isinstance(tree, exp.Sum) and _is_scalar_expression(tree.this): | ||
| return AggregationType.SUM, _col_name(tree.this), None, False |
| return node.sql() | ||
|
|
||
|
|
||
| def _is_scalar_expression(node: exp.Expression) -> bool: |
There was a problem hiding this comment.
This classifies "scalar" by blocklisting exp.AggFunc/exp.Window rather than allowlisting known-safe node types. Any aggregate sqlglot doesn't specifically model (LISTAGG, vendor/custom UDAFs) parses as generic exp.Anonymous and gets misclassified as scalar, which silently reintroduces the double-aggregation bug this PR is fixing.
Maybe also worth covering scalar subqueries (e.g. SUM((SELECT x FROM other_table LIMIT 1))) pass this check too and get embedded verbatim as expr.
I suggest inverting to an explicit allowlist of node types known to be safe as a scalar expression body, rather than trying to enumerate everything unsafe.
| return dialect_expr | ||
| return ossie_expr.dialects[0] if ossie_expr.dialects else None | ||
|
|
||
| _SQL_DIALECTS = { |
There was a problem hiding this comment.
OSSIE_SQL_2026 is missing from this set, which turns a currently-working case into a dropped metric.
On main today, a metric whose expression is written only in OSSIE_SQL_2026 converts fine, because _get_expression() falls back to dialects[0]. I checked with the CLI:
metrics:
- name: revenue
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: SUM(orders.amount)main: one metric, type_params.expr = amount. With this PR, _get_dialect_expression() returns that entry, dialect in self._SQL_DIALECTS is false, and the metric is dropped with UNSUPPORTED_METRIC_EXPRESSION.
The non-SQL dialects (MDX, MAQL, DAX, TABLEAU, SIGMA, THOUGHTSPOT) are rightly excluded, but OSSIE_SQL_2026 is the spec's own portable SQL, based on ANSI SQL:2003 Core (#439, #440), and expression_language.md asks every implementation to support the Ossie dialect. #443, #446 and #447 added it to the equivalent allowlists in orionbelt, databricks and snowflake for this exact reason, so dbt would be the one converter left out.
Suggested fix is one line:
| _SQL_DIALECTS = { | |
| _SQL_DIALECTS = { | |
| OssieDialect.ANSI_SQL, | |
| OssieDialect.OSSIE_SQL_2026, | |
| OssieDialect.BIGQUERY, | |
| OssieDialect.DATABRICKS, | |
| OssieDialect.SNOWFLAKE, | |
| } |
Unrelated to this point, but worth flagging since it is the same function: #464 changes _get_expression() on main so that OSSIE_SQL_2026 is preferred over a vendor dialect rather than resolved by array position (#461). That PR and this one touch the same lines, so whichever lands second will need a rebase — happy for that to be mine.

Summary
Fixes the dbt converter's complex-expression fallback so it does not encode an already aggregated Ossie metric as both a MetricFlow
exprand a secondagg.SUM(CASE WHEN ... THEN amount ELSE 0 END)becomesagg=sumplusexpr=CASE WHEN ... THEN amount ELSE 0 END.SUMfallback. Composite, nested, non-aggregate, unsupported-modifier, and non-SQL metric expressions are omitted withUNSUPPORTED_METRIC_EXPRESSIONinstead of silently changing semantics.Before:
After:
The invariant is that a MetricFlow SIMPLE metric has exactly one aggregation boundary:
expris scalar andaggsupplies the aggregation.Related Issues
Fixes #430
Checklist
Specification
SUMsemanticsOntology
Converters
Validation
Documentation
Examples
Tests
Compliance
AI disclosure
Per the ASF Generative Tooling Guidance, this contribution was prepared with AI assistance. I reviewed the converter semantics, implementation, tests, and generated diff, and verified the results by running the full dbt suite locally.